//
//  NetworkTools.swift
//  SinaWeibo
//
//  Created by 小果 on 16/2/9.
//  Copyright © 2016年 小果. All rights reserved.
//

import UIKit
import AFNetworking
import ReactiveCocoa

enum RequestMethod: String {
    case GET = "GET"
    case POST = "POST"
}

/// 网络工具类
class NetworkTools: AFHTTPSessionManager {
    
    // MARK: - app的信息
    private let clientId = "3756374226"
    private let appSecret = "9359552b3643797a6506d1708ed25392"
    // 回调地址
    let redirectUri = "http://www.baidu.com"

    /// 单例
    static let sharedTools: NetworkTools = {
        // 指定 baseURL
        var instance = NetworkTools(baseURL: nil)
        // 设置反序列化的支持格式
        instance.responseSerializer.acceptableContentTypes?.insert("text/plain")
        
        return instance
    }()
    
    // MARK: - 发布微博
    ///  发布微博
    ///
    ///- parameter status: 要发布的微博的文本，切记不能超过140个字，且需要百分号来进行转义(AFN会自动进行的)
    /// - parameter image: 如果有图片就上传
    ///  - returns: RAC Signal
    /// - see: [http://open.weibo.com/wiki/2/statuses/update](http://open.weibo.com/wiki/2/statuses/update)
    /// - see: [http://open.weibo.com/wiki/2/statuses/upload](http://open.weibo.com/wiki/2/statuses/upload)
    func sendStatus(status: String, image:UIImage?) -> RACSignal {
        let params = ["status": status]
        // 如果没有图片，就上传文本微博
        if image == nil {
            // 文本微博
            return request(.POST, URLString: "https://api.weibo.com/2/statuses/update.json", parameters: params)
        }else {
            // 图片微博
            return upload("https://upload.api.weibo.com/2/statuses/upload.json", parameters: params, image: image!)
        }
        
    }
    
    // MARK: - 读取微博数据
    /// - see:[http://open.weibo.com/wiki/2/statuses/home_timeline](http://open.weibo.com/wiki/2/statuses/home_timeline)
    ///  since_id	若指定此参数，则返回ID比since_id大的微博（即比since_id时间晚的微博），默认为0。
    ///  max_id    	若指定此参数，则返回ID小于或等于max_id的微博，默认为0,当此处的 id 越大的时候，刷新出的微博就越新
    func loadStatus(since_id since_id: Int, max_id: Int) ->RACSignal {
        let urlString = "https://api.weibo.com/2/statuses/home_timeline.json"
        // 创建一个空的参数字典
        var params = [String: AnyObject]()
        if since_id > 0 {
            params["since_id"] = since_id
        }else if max_id > 0 {
            params["max_id"] = max_id - 1
        }
        
        return request(.GET, URLString: urlString, parameters: params)
    }
    
    // MARK: - Oauth
    /// OAuth授权Url
    /// - see:[http://open.weibo.com/wiki/Oauth2/authorize](http://open.weibo.com/wiki/Oauth2/authorize)
    var oauthUrl: NSURL {
        let urlString = "https://api.weibo.com/oauth2/authorize?client_id=\(clientId)&redirect_uri=\(redirectUri)"
        
        return NSURL(string: urlString)!
    }
    
    // MARK: - 获取AccessToken 
    ///  -see:[http://open.weibo.com/wiki/OAuth2/access_token](http://open.weibo.com/wiki/OAuth2/access_token)
    
    func loadAccessToken(code:String) -> RACSignal{
        let urlString = "https://api.weibo.com/oauth2/access_token"
        
        let params = ["client_id": clientId,
            "client_secret": appSecret,
            "grant_type": "authorization_code",
            "code":code,
            "redirect_uri": redirectUri]
        
        return request(.POST, URLString: urlString, parameters: params, withToken: false)
    }
    ///  加载用户信息
    ///
    ///  - parameter uid:    uid
    ///
    ///  - returns: RAC Signal
    /// - see:[http://open.weibo.com/wiki/2/users/show](http://open.weibo.com/wiki/2/users/show)
    func loadUserInfo(uid: String) ->RACSignal{
        let urlString = "https://api.weibo.com/2/users/show.json"
        let params = ["uid":uid]
        
        return request(.GET, URLString: urlString, parameters: params)
    }
    
    // MARK: - 私有方法，封装AFN的网络请求的方法
    ///  在指定的参数中追加 accessToken
    ///
    ///  - parameter parameters: parameters 地址(在内部修改完成后,外部会自动跟着改变)
    ///
    ///  - returns: 是否成功,如果Token失效，则返回false
    private func appendToken(inout parameters: [String: AnyObject]?) -> Bool {
        
        // 判断单例中的token是否有效
        guard let token = userAccountViewModel.sharedUserAccount.accessToken else {
            
            return false
        }
        // 判断是否传递参数字典
        if parameters == nil {
            parameters = [String: AnyObject]()
        }
        // 后面的token都是有值的
        parameters!["access_token"] = token
        
        return true
    }
    
    /// 网络请求方法(对AFN的两种请求方法进行了封装)
    ///
    /// - parameter method:     method
    /// - parameter URLString:  URLString
    /// - parameter parameters: 参数字典
    ///
    /// - returns: RAC Signal
    private func request(method: RequestMethod, URLString: String, var parameters: [String: AnyObject]?,withToken: Bool = true) -> RACSignal {
        
        return RACSignal.createSignal({ (subscriber) -> RACDisposable! in
            
            // 0、判断是否需要token
            // 如果Token失效，则直接返回错误
            if withToken && !self.appendToken(&parameters) {
                    // 如果token为空，则发送一个token为空的错误
                    subscriber.sendError(NSError(domain: "xiao66guo.error", code: -2002, userInfo:
                        ["errorMessage":"Token 为空"]))
                    return nil
            }
            
            // 1. 成功的回调闭包
            let successCallBack = { (task: NSURLSessionDataTask, result: AnyObject?) -> Void in
                // 将结果发送给订阅者
                subscriber.sendNext(result)
                // 完成
                subscriber.sendCompleted()
            }
            
            // 2. 失败的回调闭包
            let failureCallBack = { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                print(error)
                subscriber.sendError(error)
            }
            
            // 3. 根据方法，选择调用不同的网络方法
            if method == .GET {
                self.GET(URLString, parameters: parameters, success: successCallBack, failure: failureCallBack)
            } else {
                self.POST(URLString, parameters: parameters, success: successCallBack, failure: failureCallBack)
            }
            
        return nil
        })
    }

    // 上传文件
    ///  上传文件
    ///
    ///  - parameter URLString:  URLString
    ///  - parameter parameters: parameters
    ///  - parameter image:      image 
    ///  - return: RAC Signal
    private func upload(URLString: String, var parameters: [String: AnyObject]?, image:UIImage) -> RACSignal {
        // 闭包返回值是对信号销毁时需要做的内存销毁的工作，同样是一个 block，AFN的信号可以直接返回nil
        return RACSignal.createSignal(){ (subscriber) -> RACDisposable! in
            // 0、判断是否需要token
            // 如果Token失效，则直接返回错误
            if !self.appendToken(&parameters) {
                // 如果token为空，则发送一个token为空的错误
                subscriber.sendError(NSError(domain: "xiao66guo.error", code: -2002, userInfo:
                    ["errorMessage":"Token 为空"]))
                return nil
            }
            
            // 1、调用AFN的上传文件的方法
            self.POST(URLString, parameters: parameters, constructingBodyWithBlock: { (formData) -> Void in
                // 将要上传的图像转换成二进制数据
                let data = UIImagePNGRepresentation(image)!
                
                // formData 是遵守协议的对象，是AFN内部直接提供的，在使用的时候只需要按照协议方法传递相应的参数即可
                /**1、要上传的二进制数据
                   2、服务器的字段名，在开发的时候可以咨询后台
                   3、保存在服务器的文件名，一般后台会允许随便去写的
                   4、mineType ：客户端通知服务器要上传文件的类型，如果不想告诉服务器的类型，可以直接使用 application/octet-stream(这个可以保证传任何文件的类型都可以)
                */
                formData.appendPartWithFileData(data, name: "pic", fileName: "哈哈", mimeType: "application/octet-stream")
                
                
                }, success: { (_, result) -> Void in
                    
                    subscriber.sendNext(result)
                    subscriber.sendCompleted()
                    
                }, failure: { (_, error) -> Void in
                    printLog(error, logError: true)
                    
                    subscriber.sendError(error)
            })
            
            return nil
        }
    }
}
